﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AddIn.EA.Framework;
using System.Configuration;
using System.Xml.Serialization;
using System.IO;

namespace AddIn.EA.Architecture.ComponentLogic.StandardProject
{
    public class StandardProject : IDisposable
    {
        #region Local Objects
        private static RepositoryManager templateRepository;
        public static RepositoryManager TemplateRepository
        {
            get
            {
                if (templateRepository == null)
                    templateRepository = RepositoryManager.OpenRepository(@"C:\Program Files\BMFBovespa\AddIn.EA\Resources\AddInCRUDTemplate.eap");
                return templateRepository;
            }
        }
        private RepositoryManager repository;
        #endregion

        #region Constructor
        public StandardProject(RepositoryManager repository)
        {
            this.repository = repository;
        }
        #endregion

        #region Methods
        public void ApplyEntityModelToPackageStructure(BusinessEntityStandardProject itemEntity, ElementModel.Package viewModel)
        {
            foreach (Builders.ElementBuilder itemBuilder in itemEntity.Builders)
            {
                itemBuilder.Validate();
                itemBuilder.BuildStructure(viewModel, TemplateRepository, itemEntity);
            }
        }
        public void SaveProject(Project project, String fileName)
        {
            SerializeObject(typeof(Project), project, fileName);
        }
        public Project OpenProject(String filename)
        {
            Project result = null;

            if (File.Exists(filename))
                result = DeserializeObject(typeof(Project), filename) as Project;

            return result;
        }
        public void SerializeObject(Type type, Object obj, String path)
        {
            FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write);
            XmlSerializer serializer = new XmlSerializer(type);
            serializer.Serialize(stream, obj);
            stream.Close();
        }
        public object DeserializeObject(Type type, String path)
        {
            Object result = null;
            FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            XmlSerializer serializer = new XmlSerializer(type);
            result = serializer.Deserialize(stream);
            stream.Close();
            return result;
        }

        public void ApplyPackageStructureToEA(ElementModel.Package viewModel, Framework.Package basePackage)
        {
            ApplyPackage(viewModel.Packages, basePackage);
        }
        /// <summary>
        /// This method apply the ElementModel structure to the EA structure applying the elements and packages defined.
        /// </summary>
        /// <param name="list">The list of packages according ElementModel structure</param>
        /// <param name="basePackage">The EA Package designated to receive the result.</param>
        /// <remarks>
        /// The process of converting the model to EA structure, reads all the packages provided at the parameter and for each package,
        /// checks and creates all the child packages first than it's elements. This behavior makes possible to test the package structure
        /// after get all it's elements created.
        /// </remarks>
        private void ApplyPackage(List<ElementModel.Package> list, Package basePackage)
        {
            if (list != null && list.Count > 0)
            {
                foreach (ElementModel.Package itemPackage in list)
                {
                    Package eaPackage = EAConverter.EAConverterFactory.GetConverter(itemPackage).ConvertObject(itemPackage, basePackage) as Package;
                    if (itemPackage.Packages != null && itemPackage.Packages.Count > 0)
                        ApplyPackage(itemPackage.Packages, eaPackage);

                    if (itemPackage.Elements != null && itemPackage.Elements.Count > 0)
                    {
                        foreach (ElementModel.Element itemElement in itemPackage.Elements)
                        {
                            Framework.Element appliedElement = EAConverter.EAConverterFactory.GetConverter(itemElement).ConvertObject(itemElement, eaPackage) as Framework.Element;
                        }
                    }

                    #region Create DataContracts Request/Response inheritance to DataContract root element.
                    if (eaPackage.Name.CompareTo("DataContract") == 0)
                    {
                        foreach (Framework.Element dataContractElement in eaPackage.Elements)
                        {
                            Framework.Package requestPackage = eaPackage.GetPackageByName("Request");
                            if (requestPackage != null)
                            {
                                Framework.Element dataContractRequestElement = requestPackage.Elements.Find(it => it.Name.CompareTo(dataContractElement.Name + "Request") == 0);
                                if (dataContractRequestElement != null)
                                {
                                    //Framework.Connector connector = dataContractRequestElement.AddConnector(dataContractElement, Connector.ConnectorType.Generalization, Connector.ConnectorDirection.SourceDestination);
                                    dataContractRequestElement.Update();
                                }
                            }
                            Framework.Package responsePackage = eaPackage.GetPackageByName("Response");
                            if (responsePackage != null)
                            {
                                Framework.Element dataContractResponseElement = responsePackage.Elements.Find(it => it.Name.CompareTo(dataContractElement.Name + "Response") == 0);
                                if (dataContractResponseElement != null)
                                {
                                    //Framework.Connector connector = dataContractResponseElement.AddConnector(dataContractElement, Connector.ConnectorType.Generalization, Connector.ConnectorDirection.SourceDestination);
                                    dataContractResponseElement.Update();
                                }
                            }
                        }
                    }
                    #endregion
                    #region Create ServiceContract/ServiceImplementation inheritance.
                    if (eaPackage.Name.CompareTo("Service") == 0)
                    {
                        Framework.Package serviceContractPackage = eaPackage.GetPackageByName("ServiceContract");
                        Framework.Package serviceImplementationPackage = eaPackage.GetPackageByName("ServiceImplementation");
                        if (serviceContractPackage != null && serviceImplementationPackage != null)
                        {
                            foreach (Framework.Element itemServiceContract in serviceContractPackage.Elements)
                            {
                                Framework.Element serviceImplementationElement = serviceContractPackage.Elements.Find(it => it.Name.CompareTo(itemServiceContract.Name.Substring(1, itemServiceContract.Name.Length - 1)) == 0);
                                if (serviceImplementationElement != null)
                                {
                                    //Framework.Connector connector = serviceImplementationElement.AddConnector(itemServiceContract, Connector.ConnectorType.Generalization, Connector.ConnectorDirection.SourceDestination);
                                    serviceImplementationElement.Update();
                                }
                            }
                        }
                    }
                    #endregion

                    eaPackage.Update();
                }
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (templateRepository != null)
                templateRepository.Dispose();
            if (repository != null)
                repository.Dispose();
        }

        #endregion
    }
}
